package cnu.cse.crawler.manager;

import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import cnu.cse.crawler.xedata.XeAttachedFile;

public class FileDownloadManager 
{
	///////////////////////////////////////////// Member /////////////////////////////////////////////
	//
	//
	
	private static FileDownloadManager instance = new FileDownloadManager();
	
	private static final int BUFFER_SIZE = 1024;
	
	private String attachedBinariesAbsolutePath = ".";
	private String attachedImagesAbsolutePath = ".";
	
	
	
	
	
	
	////////////////////////////////// Constructor and Initializer ///////////////////////////////////
	//
	//
		
	private FileDownloadManager()
	{
		
	}
	
	public static FileDownloadManager getInstance()
	{
		return instance;
	}
	
	public void initAttachedFileAbsolutePath(String attachedBinariesAbsolutePath, String attachedImagesAbsolutePath)
	{
		this.attachedBinariesAbsolutePath = attachedBinariesAbsolutePath;
		this.attachedImagesAbsolutePath = attachedImagesAbsolutePath;
	}
	
	
	
	
	
	
	//////////////////////////////////////// Private Methods ////////////////////////////////////////
	//
	//

    private String getMD5Hash(String str)
    {
    	String MD5 = null;
    	
    	try
    	{
    		MessageDigest md = MessageDigest.getInstance("MD5");
    		md.update(str.getBytes()); 
    		byte byteData[] = md.digest();
    		StringBuffer sb = new StringBuffer();
  
    		for(int i = 0 ; i < byteData.length ; i++)
    		{
    			sb.append(Integer.toString((byteData[i]&0xff) + 0x100, 16).substring(1));
    		}
    		
    		MD5 = sb.toString();
    		
    	}
    	catch(NoSuchAlgorithmException e)
    	{
    		e.printStackTrace();
    	}
    	
    	return MD5;
    }

    private Long fileDownload(String fileUrl, String localFileName, String destinationDir) 
    {
    	OutputStream outStream = null;
    	URLConnection  urlCon = null;
    	InputStream inStream = null;
    	
    	try 
    	{
    		URL url;
    		byte[] buffer;
    		int readSize = 0;
    		Long writeSize = 0L;
    		url= new URL(fileUrl);
    		
    		outStream = new BufferedOutputStream(new FileOutputStream(destinationDir + "\\" + localFileName));
    		urlCon = url.openConnection();
    		inStream = urlCon.getInputStream();
    		buffer = new byte[BUFFER_SIZE];
    		
    		while ((readSize = inStream.read(buffer)) != -1) 
    		{
    			outStream.write(buffer, 0, readSize);
    			writeSize += readSize;
    		}
    		
    		return writeSize;
    	}
    	catch (Exception e) 
    	{
    		e.printStackTrace();
    		return -1L;
        }
    	finally 
    	{
            try 
            {
            	inStream.close();
            	outStream.close();
            }
            catch (IOException e) 
            {
            	e.printStackTrace();
            }
        }
    }
    
    private boolean createModuleDirectoryInBinariesBase(Long serial)
    {
    	String modulePath = attachedBinariesAbsolutePath + "\\" + serial.toString();
    	File moduleDir = new File(modulePath);
    	
    	boolean result = true;
    	if (moduleDir.exists())
    	{
    		// do nothing and return true
    	}
    	else
    	{
    		result = moduleDir.mkdir();
    	}
    	
    	return result;
    }
    
    private boolean createDocumentDirectoryInBinariesBase(Long moduleSerial, Long documentSerial)
    {
    	String modulePath = attachedBinariesAbsolutePath + "\\" + moduleSerial.toString();
    	String documentPath = modulePath + "\\" + documentSerial.toString();
    	
    	File moduleDir = new File(modulePath);
    	File documentDir = new File(documentPath);
    	
    	boolean result = true;
    	if (moduleDir.exists())
    	{
    		if (documentDir.exists())
    		{
    			// do nothing and return true
    		}
    		else
    		{    		
    			result = documentDir.mkdir();
    		}
    	}
    	else
    	{
    		result = false;
    	}
    	
    	return result;
    }
    
    
    
    
    
    
	//////////////////////////////////////// Public Methods ////////////////////////////////////////
	//
	//

    public boolean fileDownloadIntoLocalDisk(String baseUrl, XeAttachedFile attachedFile, Long moduleSerial, Long documentSerial)
    {
    	boolean result = false;
    
    	String fileUrl = baseUrl + attachedFile.getSourceFilePath();
    	int slashIndex = fileUrl.lastIndexOf('/');
    	int periodIndex = fileUrl.lastIndexOf('.');
    	
    	if (periodIndex >= 1 &&  slashIndex >= 0 && slashIndex < fileUrl.length()-1)
    	{
    		if (createModuleDirectoryInBinariesBase(moduleSerial) 
    			&& createDocumentDirectoryInBinariesBase(moduleSerial, documentSerial))
    		{
    			String hashFileName = getMD5Hash(fileUrl);
    			String uploadedFilePath = attachedBinariesAbsolutePath + "\\" + moduleSerial.toString() + "\\" + documentSerial.toString();
    			Long fileSize = fileDownload(fileUrl, hashFileName, uploadedFilePath);
   
    	    	attachedFile.setFileSize(fileSize);
    			attachedFile.setHashFileName(hashFileName);
    			attachedFile.setUploadedFileName("/" + moduleSerial.toString() + "/" + documentSerial.toString() + "/" + hashFileName);
    	    	
    			result = true;
    		}
    		else
    		{
    			System.err.println("fail file directory creation...");
    		}
    	}
    	else
    	{
    		System.err.println("url path is not corecte...");
    	}
    	
    	return result;
    }
        
    public int imageDownloadFromUrl(String imageUrl, Long moduleSerial, Long documentSerial)
    {
    	// do nothing
    	
    	return 0;
    }
    
    
    
}
